package com.zwxu.upload;

import com.alibaba.fastjson.JSON;
import com.amazonaws.ResetException;
import com.amazonaws.services.s3.AmazonS3;
import com.amazonaws.services.s3.model.*;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import javax.servlet.http.HttpServletRequest;
import java.io.*;


@RestController
public class UploadController {

    public static final String UPLOAD_DIR = "upload_dir";
    public static final String BUCKET_NAME = "data";
    public static final String KEY_PREFIX = "test/%s";
    public static final Object lock = new Object();
    private static final String SOURCE = "source";
    @Autowired
    private AmazonS3ClientInstance amazonS3ClientInstance;

    @RequestMapping("/uploadToLocal")
    public  String uploadToLocal(ResumableInfo resumableInfo,HttpServletRequest request) throws Exception {
        String result = "";

        int chunkNumber = resumableInfo.getResumableChunkNumber();

        ResumableInfo info = getResumableInfo(resumableInfo);

        RandomAccessFile raf = new RandomAccessFile(info.getResumableFilePath(), "rw");

        //实现分段写入
        raf.seek((chunkNumber - 1) * info.getResumableChunkSize());

        //Save to file
        InputStream is = request.getInputStream();
        long readed = 0;
        long content_length = request.getContentLength();
        byte[] bytes = new byte[1024 * 100];
        while (readed < content_length) {
            int r = is.read(bytes);
            if (r < 0) {
                break;
            }
            raf.write(bytes, 0, r);
            readed += r;
        }
        raf.close();


        //Mark as uploaded.
        info.getUploadedChunks().add(new ResumableInfo.ResumableChunkNumber(chunkNumber));
        if (info.checkIfUploadFinished()) { //Check if all chunks uploaded, and change filename
            ResumableInfoStorage.getInstance().remove(info);
            System.out.println("final chunk: " + (chunkNumber - 1));
            System.out.println("final chunkSize: " + info.getResumableChunkSize());
            result = "All finished.";
        } else {
            result = "Upload";
        }
        return result;
    }



    @RequestMapping("/uploadToCeph")
    public String uploadToCeph(ResumableInfo resumableInfo,HttpServletRequest request) {
        long start = System.currentTimeMillis();
        AmazonS3 client = client = amazonS3ClientInstance.getClient();
        int resumableCurrentChunkSize = resumableInfo.getResumableCurrentChunkSize();
        int resumableChunkNumber = resumableInfo.getResumableChunkNumber();
        String result = "";
        //InvalidPart
        ResumableInfo info = getResumableInfo(resumableInfo);
        try {

            InputStream is = request.getInputStream();
            synchronized(lock){
                //InvalidPart else 出现多个uploadid
                if (info.getUploadedChunks().size() == 0) {
                    InitiateMultipartUploadRequest initRequest = new InitiateMultipartUploadRequest(BUCKET_NAME,
                            String.format(KEY_PREFIX, info.getResumableFilename()));
                    InitiateMultipartUploadResult initResponse = client.initiateMultipartUpload(initRequest);
                    info.setUploadId(initResponse.getUploadId());
                }

                UploadPartRequest uploadRequest = new UploadPartRequest()
                        .withBucketName(BUCKET_NAME)
                        .withKey(String.format(KEY_PREFIX, info.getResumableFilename()))
                        .withUploadId(info.getUploadId())
                        .withPartNumber(resumableChunkNumber)
                        //.withFileOffset(filePosition)
                        .withInputStream(is)
                        .withPartSize(resumableCurrentChunkSize);


                if(!info.getUploadedChunks().contains(new ResumableInfo.ResumableChunkNumber(resumableChunkNumber))){
                    long uploadStart = System.currentTimeMillis();
                    UploadPartResult uploadPartResult = client.uploadPart(uploadRequest);

                    info.addPartETag(uploadPartResult.getPartETag());
                    System.out.println(JSON.toJSONString(uploadPartResult.getPartETag()));
                    System.out.println(" upload: "+ (System.currentTimeMillis() - uploadStart));
                    info.addUploadedChunks(new ResumableInfo.ResumableChunkNumber(resumableChunkNumber));
                }

            }


            if (info.checkIfUploadFinished()) { //Check if all chunks uploaded, and change filename
                // Complete the multipart upload.
                CompleteMultipartUploadRequest compRequest = new CompleteMultipartUploadRequest(BUCKET_NAME,
                        String.format(KEY_PREFIX, info.getResumableFilename()),
                        info.getUploadId(), info.getPartETags());

                System.out.println(JSON.toJSONString(info.getPartETags()));
                client.completeMultipartUpload(compRequest);
                ResumableInfoStorage.getInstance().remove(info);
                result = "All finished.";
            } else {
                result = "Upload";
            }
        }catch (ResetException e){
                System.out.println("cancel");
        }catch (Exception e){
            ResumableInfoStorage.getInstance().remove(info);
            AbortMultipartUploadRequest abortMultipartUploadRequest = new AbortMultipartUploadRequest(BUCKET_NAME,
                    String.format(KEY_PREFIX, info.getResumableFilename()),
                    info.getUploadId());
            client.abortMultipartUpload(abortMultipartUploadRequest);
        }
        return result;
    }



    private ResumableInfo getResumableInfo(ResumableInfo resumableInfo)  {
        String base_dir = UPLOAD_DIR;
        //System.out.println("分段:" + resumableInfo.getResumableChunkNumber() + ":" + resumableInfo.getResumableCurrentChunkSize()) ;
        //Here we add a ".temp" to every upload file to indicate NON-FINISHED
        new File(base_dir).mkdir();
        String resumableFilePath = new File(base_dir, resumableInfo.getResumableFilename()).getAbsolutePath() + ".temp";
        resumableInfo.setResumableFilePath(resumableFilePath);
        ResumableInfoStorage storage = ResumableInfoStorage.getInstance();

        ResumableInfo info = storage.get(resumableInfo);
        return info;
    }
}

